#r "office"
#r "Microsoft.Office.Interop.Word"
//#I "C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools for Office\PIA\Office12"
open System
open System.Diagnostics
open System.IO
open System.Reflection
open Microsoft.Office.Interop.Word
open System.Collections.Generic



let getStyle (parag : Paragraph) = parag.Style :?> Style

let nl = Environment.NewLine

let windir = Environment.GetEnvironmentVariable("windir")
let msbuild = Path.Combine(windir, @"Microsoft.NET\Framework\v3.5\msbuild.exe")

let doWordFile filename =
    let app = new ApplicationClass()
    
    let dir = Path.GetDirectoryName(filename)
    let newFilename = Path.GetFileNameWithoutExtension(filename) + "_new.doc"
    let newFilename = Path.Combine(dir, newFilename)
    
    File.Copy(filename, newFilename, true)
    
    let doc = app.Documents.Open(ref (newFilename :> obj))
    
    use docCloser = 
        { new IDisposable with 
            Dispose() = 
                doc.TrackRevisions <- true
                doc.ShowRevisions <- true
                doc.Save()
                doc.Close() }
    doc.TrackRevisions <- false
    doc.ShowRevisions <- false

    let styles = [ for x in doc.Styles -> x ]
    let stylesLookup = new Dictionary<string, Style>()
    
    let setStyle (parag : Paragraph) name =
        let style = 
            if stylesLookup.ContainsKey(name) then
               stylesLookup.[name]
            else
                let style = 
                    styles |> Seq.find (fun x -> x.NameLocal = name)
                stylesLookup.Add(name, style)
                style
        parag.Range.Style <- ref (style :> obj)

    let insertText index text insertType =
        let parag = doc.Content.Paragraphs.[index]
        
        match text with
        | [ text ] -> 
            parag.Range.Text <- text + nl
            let parag = doc.Content.Paragraphs.[index]
            setStyle parag (insertType + " Single") 
        | [ first; last ] -> 
            let firstParag = doc.Content.Paragraphs.Add(ref (parag.Range :> obj))
            
            firstParag.Range.Text <- first + nl
            parag.Range.Text <- last + nl
            
            let parag, lastParag = doc.Content.Paragraphs.[index], doc.Content.Paragraphs.[index + 1]
            setStyle parag (insertType + " First") 
            setStyle lastParag (insertType + " Last") 
        | first :: rest ->
            let firstParag = doc.Content.Paragraphs.Add(ref (parag.Range :> obj))
            let middleParag = doc.Content.Paragraphs.Add(ref (parag.Range :> obj))
            let middle = 
                Seq.take (rest.Length - 1) rest 
                |> Seq.map (fun s -> s + nl) 
                |> String.concat ""
            let restLength = rest.Length
            let last = List.nth rest (restLength - 1)
            printfn "%s %s %s" first middle last
            firstParag.Range.Text <- first + nl
            middleParag.Range.Text <- middle
            parag.Range.Text <- last + nl

            for x in index + 1 .. index + restLength - 1 do
                setStyle (doc.Content.Paragraphs.[x]) insertType
            
            let parag, lastParag = 
                doc.Content.Paragraphs.[index], 
                doc.Content.Paragraphs.[index + restLength]
            setStyle parag (insertType + " First") 
            setStyle lastParag (insertType + " Last")
        | _ -> failwith "no text"
        
    let mutable index = 1
    while (index <= doc.Content.Paragraphs.Count) do
        let parag = doc.Content.Paragraphs.[index]
        let style = getStyle parag
        
        if style.NameLocal = "InsertCode" then
            let path = parag.Range.Text.Trim()
            if path <> "" then
                printfn "Doing: '%s'" path
                if path.StartsWith("Result:") then
                    let path = path.Substring("Result:".Length).Trim()
                    let path = Path.Combine(__SOURCE_DIRECTORY__, path)
                    let dir = Path.GetDirectoryName(path)
                    let files = Directory.GetFiles(dir, "*.fsproj")
                    let projFile = match files with [| file |] -> file | _ -> failwith "no proj file"
                    let procStart = new ProcessStartInfo(FileName = msbuild, 
                                                         WorkingDirectory = dir,
                                                         Arguments = projFile,
                                                         UseShellExecute = false,
                                                         RedirectStandardOutput = true)
                    let msbuildProc = new Process(StartInfo = procStart)
                    msbuildProc.Start() |> ignore
                    let out = msbuildProc.StandardOutput.ReadToEnd()
                    printfn "all out: %s" out
                    msbuildProc.WaitForExit()
                    if msbuildProc.ExitCode = 0 then
                        let lines = out.Split([|nl|], StringSplitOptions.RemoveEmptyEntries)
                        let pairs = Seq.pairwise lines
                        let _, copyline = Seq.find (fun (x, _) -> x = "CopyFilesToOutputDirectory:") pairs
                        let arrowIndex = copyline.IndexOf("->")
                        let filepath =
                            if arrowIndex = -1 then
                                let _, copyline = pairs |> Seq.find (fun (x, _) -> x.Contains("Copying file from")) 
                                let arrowIndex = copyline.IndexOf("->")
                                copyline.Substring(arrowIndex + 3)
                            else
                                copyline.Substring(arrowIndex + 3)
                        printfn "filepath: %s" filepath
                        let procStart = new ProcessStartInfo(FileName = filepath, 
                                                             UseShellExecute = false,
                                                             RedirectStandardOutput = true)
                        let resultProc = new Process(StartInfo = procStart)
                        resultProc.Start() |> ignore
                        let out = resultProc.StandardOutput.ReadToEnd()
                        resultProc.WaitForExit()
                        if resultProc.ExitCode = 0 then
                            let out = out.Replace("\r", "")
                            let out = if out.EndsWith("\n") then out.Remove(out.Length - 1) else out
                            let out = out.Split([|'\n'|], StringSplitOptions.None) |> List.of_array
                            insertText index out "Results"
                        else
                            failwith "process failed: %s" out
                    else
                        failwith "not build: %s" out
                else
                    let path = Path.Combine(__SOURCE_DIRECTORY__, path)
                    let text = File.ReadAllLines(path) |> List.of_array
                    insertText index text "Code"

        index <- index + 1
    printfn "Finished!"

let prefix = @"C:\Users\robert\Documents\Books\Foundations of F#_2\"

let chapter03 = "23894ch03_fd.doc"
let chapter04 = "23894ch04_toAR_new.doc"
let chapter05 = "23894ch05_fd.doc"
let chapter05' = "23894ch05_fromAR.doc"
let chapter06 = "7575ch06_fd.doc"
let chapter07 = "23894ch07_fd.doc"
let chapter08 = "23894ch08_fd.doc"
let chapter09 = "23894ch09_fd.doc"
let chapter10 = "23894ch10_fd.doc"
let chapter11 = "23894ch11_fd.doc"
let chapter12 = "23894ch12_fd.doc"
let chapter13 = "23894ch13_fd.doc"
let chapter15 = "23894ch15_fd.doc"

do doWordFile (prefix + chapter07)
